from fastapi import APIRouter, Depends, HTTPException, status, Query, Path, Form
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, and_, or_
from typing import Optional, Dict, Any
from datetime import datetime
import json

from app.models.db import get_async_session
from app.models.db import KnowledgeBase, KnowledgeItem, User, Role, UserRole
from app.models.user import current_active_user
from app.utils.auth import get_user_role_codes

router = APIRouter(
    prefix="/knowledge",
    tags=["知识库管理"]
)

# =============== 知识库管理 ===============

@router.get("/bases", response_model=Dict[str, Any])
async def list_knowledge_bases(
    search: Optional[str] = Query(None, description="按名称搜索"),
    status_filter: Optional[int] = Query(None, description="状态过滤：0/1"),
    session: AsyncSession = Depends(get_async_session),
    current_user: User = Depends(current_active_user)
):
    """分页获取知识库列表 - 带权限控制"""
    try:
        # 获取用户角色名称
        user_roles = await get_user_role_codes(str(current_user.id), session)
        user_role_list = user_roles.split(",") if user_roles else []
        
        # 获取用户角色ID列表（用于与allowed_roles比较）
        user_role_ids = []
        if user_role_list:
            role_query = select(Role.id).where(Role.name.in_(user_role_list))
            role_result = await session.execute(role_query)
            user_role_ids = [str(row[0]) for row in role_result.all()]
        
        # 构建基础查询
        query = select(KnowledgeBase).where(KnowledgeBase.status == 1)  # 只显示启用的知识库
        
        # 权限过滤：只显示用户有权限访问的知识库
        permission_conditions = []
        
        # 1. 公开的知识库所有人都可以访问
        permission_conditions.append(KnowledgeBase.access_level == 'public')
        
        # 2. 如果用户有角色，检查私有和受限知识库
        if user_role_ids:
            # 私有和受限知识库需要检查 allowed_roles（存储的是角色ID）
            for role_id in user_role_ids:
                if role_id:
                    # 检查 allowed_roles 数组中是否包含用户的角色ID
                    permission_conditions.append(
                        and_(
                            or_(KnowledgeBase.access_level == 'private', KnowledgeBase.access_level == 'role_based'),
                            func.JSON_CONTAINS(KnowledgeBase.allowed_roles, f'"{role_id}"')
                        )
                    )
        
        # 3. 用户创建的知识库（如果有 created_by 字段）
        permission_conditions.append(KnowledgeBase.created_by == str(current_user.id))
        
        # 应用权限过滤
        query = query.where(or_(*permission_conditions))
        
        # 应用其他过滤条件
        if search:
            query = query.where(KnowledgeBase.name.like(f"%{search}%"))
        if status_filter is not None:
            query = query.where(KnowledgeBase.status == status_filter)
        
        query = query.order_by(KnowledgeBase.updated_at.desc())

        # 获取所有符合条件的数据
        result = await session.execute(query)
        items = result.scalars().all()

        # 为每个知识库添加条目数量
        enriched_data = []
        for kb in items:
            kb_dict = kb.to_dict()
            
            # 查询该知识库的条目数量
            count_query = select(func.count()).where(
                KnowledgeItem.knowledge_base_id == kb.id,
                KnowledgeItem.status == 1  # 只计算已发布的条目
            )
            count_result = await session.execute(count_query)
            item_count = count_result.scalar() or 0
            
            kb_dict['item_count'] = item_count
            enriched_data.append(kb_dict)

        return {
            "success": True,
            "data": enriched_data,
            "total": len(enriched_data),
            "user_roles": user_roles  # 返回用户角色信息，便于前端调试
        }
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"获取知识库列表失败: {str(e)}")


@router.post("/bases", response_model=Dict[str, Any])
async def create_knowledge_base(
    name: str = Form(...),
    description: Optional[str] = Form(None),
    category: Optional[str] = Form("general"),
    status_value: int = Form(1),
    search_weight: float = Form(1.0),
    access_level: str = Form("public"),
    allowed_roles: Optional[str] = Form(None, description="JSON数组字符串，如 [\"admin\", \"editor\"]"),
    session: AsyncSession = Depends(get_async_session),
    current_user: User = Depends(current_active_user)
):
    """创建知识库"""
    try:
        kb = KnowledgeBase(
            name=name,
            description=description,
            category=category,
            status=status_value,
            search_weight=search_weight,
            access_level=access_level,
            allowed_roles=json.loads(allowed_roles) if allowed_roles else None,
            created_by=str(current_user.id) if hasattr(current_user, 'id') else None,
            created_at=datetime.now(),
            updated_at=datetime.now(),
        )
        session.add(kb)
        await session.commit()
        await session.refresh(kb)
        return {"success": True, "data": kb.to_dict(), "message": "创建成功"}
    except Exception as e:
        await session.rollback()
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"创建知识库失败: {str(e)}")


@router.put("/bases/{base_id}", response_model=Dict[str, Any])
async def update_knowledge_base(
    base_id: int = Path(..., description="知识库ID"),
    name: Optional[str] = Form(None),
    description: Optional[str] = Form(None),
    category: Optional[str] = Form(None),
    status_value: Optional[int] = Form(None),
    search_weight: Optional[float] = Form(None),
    access_level: Optional[str] = Form(None),
    allowed_roles: Optional[str] = Form(None),
    session: AsyncSession = Depends(get_async_session),
    current_user: User = Depends(current_active_user)
):
    """更新知识库"""
    try:
        result = await session.execute(select(KnowledgeBase).where(KnowledgeBase.id == base_id))
        kb = result.scalar_one_or_none()
        if not kb:
            raise HTTPException(status_code=404, detail="知识库不存在")

        if name is not None: kb.name = name
        if description is not None: kb.description = description
        if category is not None: kb.category = category
        if status_value is not None: kb.status = status_value
        if search_weight is not None: kb.search_weight = search_weight
        if access_level is not None: kb.access_level = access_level
        if allowed_roles is not None:
            kb.allowed_roles = json.loads(allowed_roles) if allowed_roles else None
        kb.updated_at = datetime.now()

        session.add(kb)
        await session.commit()
        return {"success": True, "data": kb.to_dict(), "message": "更新成功"}
    except HTTPException:
        raise
    except Exception as e:
        await session.rollback()
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"更新知识库失败: {str(e)}")


@router.delete("/bases/{base_id}", response_model=Dict[str, Any])
async def delete_knowledge_base(
    base_id: int = Path(..., description="知识库ID"),
    session: AsyncSession = Depends(get_async_session),
    current_user: User = Depends(current_active_user)
):
    """删除知识库"""
    try:
        result = await session.execute(select(KnowledgeBase).where(KnowledgeBase.id == base_id))
        kb = result.scalar_one_or_none()
        if not kb:
            raise HTTPException(status_code=404, detail="知识库不存在")
        await session.delete(kb)
        await session.commit()
        return {"success": True, "message": "删除成功"}
    except HTTPException:
        raise
    except Exception as e:
        await session.rollback()
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"删除知识库失败: {str(e)}")


# =============== 知识条目管理 ===============

@router.get("/items/{item_id}", response_model=Dict[str, Any])
async def get_knowledge_item(
    item_id: int = Path(..., description="条目ID"),
    session: AsyncSession = Depends(get_async_session),
    current_user: User = Depends(current_active_user)
):
    """获取单个知识条目详情 - 带权限控制"""
    try:
        # 获取用户角色名称
        user_roles = await get_user_role_codes(str(current_user.id), session)
        user_role_list = user_roles.split(",") if user_roles else []
        
        # 获取用户角色ID列表（用于与allowed_roles比较）
        user_role_ids = []
        if user_role_list:
            role_query = select(Role.id).where(Role.name.in_(user_role_list))
            role_result = await session.execute(role_query)
            user_role_ids = [str(row[0]) for row in role_result.all()]
        
        # 构建知识库权限过滤条件
        kb_permission_conditions = []
        
        # 1. 公开的知识库
        kb_permission_conditions.append(KnowledgeBase.access_level == 'public')
        
        # 2. 用户有权限的私有/受限知识库
        if user_role_ids:
            for role_id in user_role_ids:
                if role_id:
                    kb_permission_conditions.append(
                        and_(
                            or_(KnowledgeBase.access_level == 'private', KnowledgeBase.access_level == 'role_based'),
                            func.JSON_CONTAINS(KnowledgeBase.allowed_roles, f'"{role_id}"')
                        )
                    )
        
        # 3. 用户创建的知识库
        kb_permission_conditions.append(KnowledgeBase.created_by == str(current_user.id))
        
        # 查询知识条目并验证权限
        result = await session.execute(
            select(KnowledgeItem).join(
                KnowledgeBase, 
                KnowledgeItem.knowledge_base_id == KnowledgeBase.id
            ).where(
                and_(
                    KnowledgeItem.id == item_id,
                    KnowledgeBase.status == 1,  # 知识库必须是启用状态
                    or_(*kb_permission_conditions)  # 用户必须有权限访问知识库
                )
            )
        )
        item = result.scalar_one_or_none()
        
        if not item:
            raise HTTPException(status_code=404, detail="知识条目不存在或您没有权限访问")
        
        return {"success": True, "data": item.to_dict()}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"获取知识条目失败: {str(e)}")


@router.get("/items", response_model=Dict[str, Any])
async def list_knowledge_items(
    skip: int = Query(0, ge=0),
    limit: int = Query(10, ge=1, le=100),
    base_id: Optional[int] = Query(None, description="所属知识库ID过滤"),
    search: Optional[str] = Query(None, description="按标题搜索"),
    status_filter: Optional[int] = Query(None, description="状态过滤：0/1/2"),
    session: AsyncSession = Depends(get_async_session),
    current_user: User = Depends(current_active_user)
):
    """分页获取知识条目列表 - 带权限控制"""
    try:
        # 获取用户角色名称
        user_roles = await get_user_role_codes(str(current_user.id), session)
        user_role_list = user_roles.split(",") if user_roles else []
        
        # 获取用户角色ID列表（用于与allowed_roles比较）
        user_role_ids = []
        if user_role_list:
            role_query = select(Role.id).where(Role.name.in_(user_role_list))
            role_result = await session.execute(role_query)
            user_role_ids = [str(row[0]) for row in role_result.all()]
        
        # 构建知识库权限过滤条件
        kb_permission_conditions = []
        
        # 1. 公开的知识库
        kb_permission_conditions.append(KnowledgeBase.access_level == 'public')
        
        # 2. 用户有权限的私有/受限知识库
        if user_role_ids:
            for role_id in user_role_ids:
                if role_id:
                    kb_permission_conditions.append(
                        and_(
                            or_(KnowledgeBase.access_level == 'private', KnowledgeBase.access_level == 'role_based'),
                            func.JSON_CONTAINS(KnowledgeBase.allowed_roles, f'"{role_id}"')
                        )
                    )
        
        # 3. 用户创建的知识库
        kb_permission_conditions.append(KnowledgeBase.created_by == str(current_user.id))
        
        # 构建查询：只获取用户有权限访问的知识库中的条目
        query = select(KnowledgeItem).join(
            KnowledgeBase, 
            KnowledgeItem.knowledge_base_id == KnowledgeBase.id
        ).where(
            and_(
                KnowledgeBase.status == 1,  # 知识库必须是启用状态
                or_(*kb_permission_conditions)  # 用户必须有权限访问知识库
            )
        )
        
        # 应用其他过滤条件
        if base_id is not None:
            query = query.where(KnowledgeItem.knowledge_base_id == base_id)
        if search:
            query = query.where(KnowledgeItem.title.like(f"%{search}%"))
        if status_filter is not None:
            query = query.where(KnowledgeItem.status == status_filter)
        else:
            # 默认只显示已发布的条目
            query = query.where(KnowledgeItem.status == 1)
        
        query = query.order_by(KnowledgeItem.updated_at.desc())

        # 计算总数
        total_query = select(func.count()).select_from(query.subquery())
        total_result = await session.execute(total_query)
        total = total_result.scalar() or 0

        # 获取分页数据
        result = await session.execute(query.offset(skip).limit(limit))
        items = result.scalars().all()

        return {
            "success": True,
            "data": [it.to_dict() for it in items],
            "total": total,
            "skip": skip,
            "limit": limit,
        }
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"获取知识条目列表失败: {str(e)}")


@router.post("/items", response_model=Dict[str, Any])
async def create_knowledge_item(
    knowledge_base_id: int = Form(...),
    title: str = Form(...),
    content: str = Form(...),
    summary: Optional[str] = Form(None),
    keywords: Optional[str] = Form(None, description="JSON数组字符串或逗号分隔"),
    tags: Optional[str] = Form(None, description="JSON数组字符串或逗号分隔"),
    source_type: str = Form("manual"),
    source_url: Optional[str] = Form(None),
    priority: int = Form(5),
    status_value: int = Form(1),
    session: AsyncSession = Depends(get_async_session),
    current_user: User = Depends(current_active_user)
):
    """创建知识条目"""
    try:
        def parse_list(value: Optional[str]):
            if not value:
                return None
            try:
                v = json.loads(value)
                if isinstance(v, list):
                    return v
            except Exception:
                pass
            # 逗号分隔
            return [s.strip() for s in value.split(',') if s.strip()]

        item = KnowledgeItem(
            knowledge_base_id=knowledge_base_id,
            title=title,
            content=content,
            summary=summary,
            keywords=parse_list(keywords),
            tags=parse_list(tags),
            source_type=source_type,
            source_url=source_url,
            priority=priority,
            status=status_value,
            created_by=str(current_user.id) if hasattr(current_user, 'id') else None,
            created_at=datetime.now(),
            updated_at=datetime.now(),
        )
        session.add(item)
        await session.commit()
        await session.refresh(item)
        return {"success": True, "data": item.to_dict(), "message": "创建成功"}
    except Exception as e:
        await session.rollback()
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"创建知识条目失败: {str(e)}")


@router.put("/items/{item_id}", response_model=Dict[str, Any])
async def update_knowledge_item(
    item_id: int = Path(..., description="条目ID"),
    knowledge_base_id: Optional[int] = Form(None),
    title: Optional[str] = Form(None),
    content: Optional[str] = Form(None),
    summary: Optional[str] = Form(None),
    keywords: Optional[str] = Form(None),
    tags: Optional[str] = Form(None),
    source_type: Optional[str] = Form(None),
    source_url: Optional[str] = Form(None),
    priority: Optional[int] = Form(None),
    status_value: Optional[int] = Form(None),
    session: AsyncSession = Depends(get_async_session),
    current_user: User = Depends(current_active_user)
):
    """更新知识条目"""
    try:
        result = await session.execute(select(KnowledgeItem).where(KnowledgeItem.id == item_id))
        item = result.scalar_one_or_none()
        if not item:
            raise HTTPException(status_code=404, detail="知识条目不存在")

        def parse_list(value: Optional[str]):
            if value is None:
                return None
            try:
                v = json.loads(value)
                if isinstance(v, list):
                    return v
            except Exception:
                pass
            return [s.strip() for s in value.split(',') if s.strip()]

        if knowledge_base_id is not None: item.knowledge_base_id = knowledge_base_id
        if title is not None: item.title = title
        if content is not None: item.content = content
        if summary is not None: item.summary = summary
        if keywords is not None: item.keywords = parse_list(keywords)
        if tags is not None: item.tags = parse_list(tags)
        if source_type is not None: item.source_type = source_type
        if source_url is not None: item.source_url = source_url
        if priority is not None: item.priority = priority
        if status_value is not None: item.status = status_value
        item.updated_at = datetime.now()

        session.add(item)
        await session.commit()
        return {"success": True, "data": item.to_dict(), "message": "更新成功"}
    except HTTPException:
        raise
    except Exception as e:
        await session.rollback()
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"更新知识条目失败: {str(e)}")


@router.delete("/items/{item_id}", response_model=Dict[str, Any])
async def delete_knowledge_item(
    item_id: int = Path(..., description="条目ID"),
    session: AsyncSession = Depends(get_async_session),
    current_user: User = Depends(current_active_user)
):
    """删除知识条目"""
    try:
        result = await session.execute(select(KnowledgeItem).where(KnowledgeItem.id == item_id))
        item = result.scalar_one_or_none()
        if not item:
            raise HTTPException(status_code=404, detail="知识条目不存在")
        await session.delete(item)
        await session.commit()
        return {"success": True, "message": "删除成功"}
    except HTTPException:
        raise
    except Exception as e:
        await session.rollback()
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"删除知识条目失败: {str(e)}") 